package br.senai.sc.controller.business;

import java.io.Serializable;
import java.math.BigInteger;

import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;

import org.jboss.seam.international.status.Messages;
import org.jboss.seam.international.status.builder.BundleKey;

import br.senai.sc.model.Permissao;
import br.senai.sc.model.Usuario;
import br.senai.sc.util.SystemConstants;

/**
 * Regras de negócio da entidade {@link Usuario}
 * 
 * @author Tiago Wanke Marques &lt;tiago.marques@sc.senai.br&gt;
 */
public class UsuarioBusiness implements Serializable {

	private static final long serialVersionUID = 1L;

	@PersistenceContext
	private EntityManager em;

	@Inject
	private Messages messages;

	/**
	 * Verifica se usuario existe.
	 * 
	 * @param usuario
	 * @return True caso o {@link Usuario} existe cadastrado no banco, false
	 *         caso contrário.
	 */
	public boolean existe(Usuario usuario) {

		if ((usuario == null) || (usuario.getIdUsuario() == null)) {
			return false;
		}

		BigInteger total = (BigInteger) em
				.createNativeQuery(
						"SELECT count(*) FROM usuario u WHERE id_usuario = :idUsuario")
				.setParameter("idUsuario", usuario.getIdUsuario())
				.getSingleResult();
		return total.intValue() > 0;
	}

	/**
	 * Verifica se a {@link Permissao} existe.
	 * 
	 * @param permissao
	 * @return True caso a {@link Permissao} exista cadastrada no banco, false
	 *         caso contrário.
	 */
	public boolean permissaoExiste(Permissao permissao) {

		if ((permissao == null) || (permissao.getIdPermissao() == null)) {
			return false;
		}

		BigInteger total = (BigInteger) em
				.createNativeQuery(
						"SELECT count(*) FROM permissao p WHERE id_permissao = :idPermissao")
				.setParameter("idPermissao", permissao.getIdPermissao())
				.getSingleResult();
		return total.intValue() > 0;
	}

	/**
	 * Verifica se já existe um login cadastrado.
	 * 
	 * @param usuario
	 * @return True caso o login existe cadastrado no banco, false caso
	 *         contrário.
	 */
	public boolean loginExiste(Usuario usuario) {
		if ((usuario == null) || (usuario.getLogin() == null)) {
			return false;
		}

		BigInteger total = (BigInteger) em
				.createNativeQuery(
						"SELECT count(*) FROM usuario u WHERE login = :login")
				.setParameter("login", usuario.getLogin()).getSingleResult();
		return total.intValue() > 0;
	}

	/**
	 * Verifica se já existe um login cadastrado, porém com id diferente.
	 * 
	 * @param usuario
	 * @return True caso o login existe no banco, porém com id diferente do
	 *         informado.
	 */
	public boolean loginIgualIdDiferenteExiste(Usuario usuario) {

		if ((usuario == null) || (usuario.getLogin() == null)
				|| (usuario.getIdUsuario() == null)) {
			return false;
		}

		BigInteger total = (BigInteger) em
				.createNativeQuery(
						"SELECT count(*) FROM usuario u WHERE login LIKE :login AND id_usuario != :idUsuario")
				.setParameter("login", usuario.getLogin())
				.setParameter("idUsuario", usuario.getIdUsuario())
				.getSingleResult();

		return total.intValue() > 0;
	}

	/**
	 * Verifica se é o administrador.
	 * 
	 * @param usuario
	 * @return True caso o {@link Usuario} seja administrador, false caso
	 *         contrário.
	 */
	public boolean isAdmin(Usuario usuario) {

		if ((usuario == null) || (usuario.getIdUsuario() == null)) {
			return false;
		}

		TypedQuery<Boolean> query = em
				.createQuery(
						"SELECT u.permissao.administracao FROM Usuario AS u WHERE u.idUsuario = :idUsuario",
						Boolean.class).setParameter("idUsuario",
						usuario.getIdUsuario());

		try {
			return query.getSingleResult().booleanValue();
		} catch (NoResultException e) {
			return false;
		}
	}

	/**
	 * Executa os métodos necessários para verificar se a {@link Usuario} pode
	 * ser salvo. Caso houver alguma inconsistência adiciona ao atributo de
	 * mensagens da classe.
	 * 
	 * @param usuario
	 * @return True caso a {@link Usuario} pode ser salvo, false caso contrário.
	 */
	public boolean podeSalvar(Usuario usuario) {

		messages.clear();
		if (!permissaoExiste(usuario.getPermissao())) {
			messages.error(new BundleKey(
					SystemConstants.PATH_TO_APPLICATION_MESSAGES,
					"usuarios.validacao.permissaoInexistente"));
		}

		if (loginExiste(usuario)) {
			messages.error(new BundleKey(
					SystemConstants.PATH_TO_APPLICATION_MESSAGES,
					"usuarios.validacao.usuarioComMesmoLogin"));
		}

		return messages.isEmpty();
	}

	/**
	 * Executa os métodos necessários para verificar se a {@link Usuario} pode
	 * ser editado. Caso houver alguma inconsistência adiciona ao atributo de
	 * mensagens da classe.
	 * 
	 * @param usuario
	 * @return True caso o {@link Usuario} pode ser editado, false caso
	 *         contrário.
	 */
	public boolean podeEditarUsuario(Usuario usuario) {

		messages.clear();

		if (!existe(usuario)) {
			messages.error(new BundleKey(
					SystemConstants.PATH_TO_APPLICATION_MESSAGES,
					"usuarios.validacao.usuarioInexistente"));
		}

		if (loginIgualIdDiferenteExiste(usuario)) {
			messages.error(new BundleKey(
					SystemConstants.PATH_TO_APPLICATION_MESSAGES,
					"usuarios.validacao.usuarioComMesmoLogin"));
		}

		if (!permissaoExiste(usuario.getPermissao())) {
			messages.error(new BundleKey(
					SystemConstants.PATH_TO_APPLICATION_MESSAGES,
					"usuarios.validacao.permissaoInexistente"));
		}

		return messages.isEmpty();
	}

	/**
	 * Executa os métodos necessários para verificar se o {@link Usuario} pode
	 * ser removido. Caso houver alguma inconsistência adiciona ao atributo de
	 * mensagens da classe.
	 * 
	 * @param usuario
	 * @return True caso a {@link Usuario} pode ser removido, false caso
	 *         contrário.
	 */
	public boolean podeRemover(Usuario usuario) {

		messages.clear();
		if (!existe(usuario)) {
			messages.error(new BundleKey(
					SystemConstants.PATH_TO_APPLICATION_MESSAGES,
					"usuarios.validacao.usuarioInexistente"));
		}

		if (isAdmin(usuario)) {
			messages.error(new BundleKey(
					SystemConstants.PATH_TO_APPLICATION_MESSAGES,
					"usuarios.validacao.removerUsuarioAdmin"));
		}

		return messages.isEmpty();
	}

}
